package br.indt.framework.ui.common;

import javax.microedition.lcdui.Graphics;

/**
 * Busy animation to wait long running operations. 
 *
 */
public class BusyAnimation extends Displayable {
	
	private Label label = null;
	private int startY = 0;
	private int labelStartX = 0;
	private int drawHeight = 0;
	
	private static final int MAX_STATE = 3;
	private static final int RADIUS_CHANGE = 15;
	private static final int CIRCLE_BORDER_WIDTH = 5;
	private static final int ANIMATION_TOP_MARGIN = 10;
	private static final int ANIMATION_BOTTOM_MARGIN = 5;
	private int state = MAX_STATE;
	private int incr = 1;
	private int animationHeight = 0;
	private Button button = null;

	private int buttonStartX = 0;
	private int buttonStartY = 0;
	
	private int[] color = {0xa4c2dd,0x6a9fcf,0x307cc0};
	
	public Button getButton() {
		return button;
	}

	/**
	 * Constructor 
	 * 
	 * @param width
	 * @param height
	 * @param listener
	 */
	public BusyAnimation(int width, int height, ButtonActionListener listener) {
		super("BusyAnimation");
		this.width = width;
		this.height = height;
		
		label =  new Label("pgslabel","Please Wait");
		label.setWidth(width - (leftMargin + rightMargin));
		label.setMargin(0, 5, 0, 5);
		button = new Button("button", "Cancel", null);
		button.setMargin(20, 3, 20, 3);
		button.setButtonActionListener(listener);
		add(button);
		
		calculateDrawingCoordinates();
	}
		
	/**
	 * Defines the text to be showed on component
	 * 
	 * @param text
	 * @param image
	 */
	public void setText(String text) {
		label.setText(text);
		calculateDrawingCoordinates();
	}
	
	/**
	 * Defines the margins of component.
	 * 
	 * @param left
	 * @param top
	 * @param right
	 * @param bottom
	 */
	public void setMargin(int left, int top, int right, int bottom) {
		super.setMargin(left, top, right, bottom);
		label.setWidth(width - (leftMargin + rightMargin));
		calculateDrawingCoordinates();
	}

	/**
	 * This method is called by main ui thread to paint the component.
	 * 
	 * @param g
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 */
	public void paint(Graphics g, int x, int y, int width, int height) {
		y = startY;
		width -= (leftMargin + rightMargin);
		x += leftMargin;
				
		g.setColor(0);
		g.drawRoundRect(x, y, width, drawHeight, 20, 20);
		g.setColor(0xEEEEEE);
		g.fillRoundRect(x + 1, y + 1, width - 1, drawHeight -1 , 20, 20);
				
		y += ANIMATION_TOP_MARGIN;
		y += animationHeight / 2;
		int radius = (MAX_STATE * RADIUS_CHANGE) - (RADIUS_CHANGE * (MAX_STATE - state));
		for(int i = MAX_STATE - state; i < MAX_STATE; i++) {
			drawCircle(g, x + width/2, y, radius, 0xEEEEEE, CIRCLE_BORDER_WIDTH, color[i]);
			radius -= RADIUS_CHANGE;
		}
		y += animationHeight / 2;
		y += ANIMATION_BOTTOM_MARGIN;
		
		label.paint(g, labelStartX, y, width, height);
		y += label.getHeight();
		
		button.setButtonWidth(width);
		button.paint(g, buttonStartX, buttonStartY, width, height);
	}
	
	private void calculateDrawingCoordinates() {
		int drawWidth = width - (leftMargin + rightMargin);
		drawHeight = label.getHeight() + button.getHeight() + animationHeight + (ANIMATION_TOP_MARGIN + ANIMATION_BOTTOM_MARGIN);
		startY = height - bottomMargin - drawHeight;
		animationHeight = ((RADIUS_CHANGE * MAX_STATE) * 2);
		labelStartX = leftMargin + ((label.getWidth() - label.getActualWidth()) /2);
		
		buttonStartX = leftMargin + ((drawWidth - button.getWidth()) /2);
		buttonStartY = startY + ANIMATION_TOP_MARGIN + animationHeight + ANIMATION_BOTTOM_MARGIN + label.getHeight();
	}
	
	private void drawCircle(Graphics g, int x, int y, int radius, int fillColor, int borderSize, int borderColor) {
		int startAngle = 0;
		int endAngle = 360;
		int startX = x - radius;
		int startY = y - radius;
		g.setColor(borderColor);
		g.fillArc(startX, startY, radius * 2, radius * 2, startAngle, endAngle);
		g.setColor(fillColor);
		g.fillArc(startX + borderSize , startY + borderSize, radius * 2 - (borderSize * 2), radius * 2 - (borderSize * 2), startAngle, endAngle);
	}
	
	public boolean animate() {
		if(state == 1 && incr == -1) {
			incr = 1;
		} else if(state == MAX_STATE && incr == 1) {
			incr = -1;
		}
		state += incr;
		return true;
	}
	
	protected Widget getWidgetAt(int x, int y) {
		if(x >= buttonStartX && x <= buttonStartX + button.getWidth()
				&& y >= buttonStartY && y <= buttonStartY + button.getHeight()) {
			return button;
		}
		return null;
	}
	
}
